﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Windows;
using Common.Utility;
using Common.ViewModel;
using DataInterpolator.Model;
using DataInterpolator.Properties;
using DataInterpolator.ViewModel.Messages;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using Microsoft.Win32;

namespace DataInterpolator.ViewModel
{
   /// <summary>
   /// This class contains properties that a View can data bind to.
   /// <para>
   /// See http://www.galasoft.ch/mvvm
   /// </para>
   /// </summary>
   public class DatabaseViewModel : ViewModelBase
   {
      private readonly IDataService _DataService;

      /// <summary>
      /// Initializes a new instance of the DatabaseViewModel class.
      /// </summary>
      public DatabaseViewModel(IDataService dataService)
      {
         _DataService = dataService;

         Messenger.Default.Register<FullRefreshMessage>(this, OnFullRefresh);

         //Request any existing data
         Messenger.Default.Send(new RequestDataMessage(OnFullRefresh));

         this.CloseWindowCommand = new RelayCommand<Window>(this.CloseWindow);
      }

      private void OnFullRefresh(FullRefreshMessage message)
      {
         InternalWellData = message.DataView.SourceCollection as MultiSelectBindingList<WellVMO>;

         string oldTitle = null;

         if (SelectedWell != null)
         {
            oldTitle = SelectedWell.Title;
            SelectedWell = null;
         }

         //Now update the comparison item if necessary
         if (_InternalWellData != null && _InternalWellData.Count > 0)
         {
            foreach (WellVMO well in _InternalWellData)
            {
               if (well.Title == oldTitle)
               {
                  SelectedWell = well;
                  break;
               }
            }

            //Pick the first if it wasnt found
            if (SelectedWell == null)
               SelectedWell = _InternalWellData[0];
         }
      }

      /// <summary>
      /// The <see cref="SelectedWell" /> property's name.
      /// </summary>
      public const string SelectedWellPropertyName = "SelectedWell";

      private WellVMO _SelectedWell = null;

      /// <summary>
      /// Sets and gets the SelectedWell property.
      /// Changes to that property's value raise the PropertyChanged event. 
      /// </summary>
      public WellVMO SelectedWell
      {
         get
         {
            return _SelectedWell;
         }

         set
         {
            if (_SelectedWell == value)
            {
               return;
            }

            _SelectedWell = value;
            RaisePropertyChanged(SelectedWellPropertyName);
         }
      }

      private MultiSelectBindingList<WellVMO> _InternalWellData = null;

      public MultiSelectBindingList<WellVMO> InternalWellData
      {
         get
         {
            return _InternalWellData;
         }
         set
         {
            //Need to move the event handlers
            if (_InternalWellData != null)
            {
               _InternalWellData.ListChanged -= OnItemChanged;
            }

            _InternalWellData = value;

            if (_InternalWellData != null)
            {
               _InternalWellData.ListChanged += OnItemChanged;
            }

            RaisePropertyChanged("InternalWellData");
         }
      }

      private void OnItemChanged(object sender, ListChangedEventArgs e)
      {
         foreach (var well in _InternalWellData)
         {
            if (well.Focus == FocusLevels.High)
            {
               SelectedWell = well;
            }
         }
      }

      private RelayCommand _NewDatabaseCommand;

      /// <summary>
      /// Gets the NewDatabaseCommand.
      /// </summary>
      public RelayCommand NewDatabaseCommand
      {
         get
         {
            return _NewDatabaseCommand
                ?? (_NewDatabaseCommand = new RelayCommand(
                () =>
                {
                   _DataService.NewDatabase();
                }));
         }
      }

      private RelayCommand _LoadDatabaseCommand;

      /// <summary>
      /// Gets the LoadDatabaseCommand.
      /// </summary>
      public RelayCommand LoadDatabaseCommand
      {
         get
         {
            return _LoadDatabaseCommand
                ?? (_LoadDatabaseCommand = new RelayCommand(
                () =>
                {
                   OpenFileDialog ofd = new OpenFileDialog();

                   ofd.InitialDirectory = Properties.Settings.Default.PrevDatabaseFile;
                   ofd.Multiselect = false;

                   if (!ofd.ShowDialog().GetValueOrDefault(false))
                      return;

                   if (ofd.FileName == null)
                   {
                      ofd.FileName = string.Empty;
                   }

                   if (_DataService.LoadDatabaseFile(ofd.FileName))
                   {
                      Properties.Settings.Default.PrevDatabaseFile = ofd.FileName;
                   }
                }));
         }
      }

      private RelayCommand _SaveDatabaseCommand;

      /// <summary>
      /// Gets the SaveDatabaseCommand.
      /// </summary>
      public RelayCommand SaveDatabaseCommand
      {
         get
         {
            return _SaveDatabaseCommand
                ?? (_SaveDatabaseCommand = new RelayCommand(
                () =>
                {
                   string filename = _DataService.SaveDatabaseFile(false);

                   if (filename != null)
                   {
                      Settings.Default.PrevDatabaseFile = filename;
                   }
                }));
         }
      }

      private RelayCommand _SaveDatabaseAsCommand;

      /// <summary>
      /// Gets the SaveDatabaseCommand.
      /// </summary>
      public RelayCommand SaveDatabaseAsCommand
      {
         get
         {
            return _SaveDatabaseAsCommand
                ?? (_SaveDatabaseAsCommand = new RelayCommand(
                () =>
                {
                   string filename = _DataService.SaveDatabaseFile(true);

                   if (filename != null)
                   {
                      Settings.Default.PrevDatabaseFile = filename;
                   }
                }));
         }
      }

      private RelayCommand _ImportLogsCommand;

      /// <summary>
      /// Gets the ImportLogsCommand.
      /// </summary>
      public RelayCommand ImportLogsCommand
      {
         get
         {
            return _ImportLogsCommand
                ?? (_ImportLogsCommand = new RelayCommand(
                () =>
                {
                   OpenFileDialog ofd = new OpenFileDialog();

                   ofd.InitialDirectory = Properties.Settings.Default.PrevLogFolder;
                   ofd.Multiselect = true;
                   ofd.Title = "Select Log Files To Load";

                   if (!ofd.ShowDialog().GetValueOrDefault(false))
                      return;

                   if (ofd.FileNames == null)
                   {
                      return;
                   }

                   if (ofd.FileNames.Length > 0)
                   {
                      Properties.Settings.Default.PrevLogFolder = Path.GetDirectoryName(ofd.FileNames[0]);
                   }

                   _DataService.ImportLogFiles(ofd.FileNames);
                }));
         }
      }

      private RelayCommand _RemoveLogsCommand;

      /// <summary>
      /// Gets the RemoveLogsCommand.
      /// </summary>
      public RelayCommand RemoveLogsCommand
      {
         get
         {
            return _RemoveLogsCommand
                ?? (_RemoveLogsCommand = new RelayCommand(
                () =>
                {
                   List<Guid> ids = new List<Guid>();

                   foreach (var well in _InternalWellData.SelectedItems)
                   {
                      ids.Add(well.ID);
                   }

                   _DataService.RemoveWells(ids);
                }));
         }
      }

      private RelayCommand<string> _UseForAllCommand;

      /// <summary>
      /// Gets the UseForAllCommand.
      /// </summary>
      public RelayCommand<string> UseForAllCommand
      {
         get
         {
            return _UseForAllCommand
                ?? (_UseForAllCommand = new RelayCommand<string>(
                p =>
                {
                   bool isDatum = false;

                   if (p == "DATUM")
                   {
                      isDatum = true;
                   }
                   else if (p == "VELOCITY")
                   {
                      isDatum = false;
                   }
                   else
                   {
                      return;
                   }

                   foreach (var well in InternalWellData)
                   {
                      if (well != SelectedWell)
                      {
                         if (isDatum)
                         {
                            well.SeismicDatum = SelectedWell.SeismicDatum;
                         }
                         else
                         {
                            well.SeismicVelocity = SelectedWell.SeismicVelocity;
                         }
                      }
                   }
                }));
         }
      }

      public RelayCommand<Window> CloseWindowCommand
      {
         get; private set;
      }

      private void CloseWindow(Window window)
      {
         if (window != null)
         {
            window.Close();
         }
      }
   }
}